# encoding=utf8

from PIL import Image, ImageSequence
import os
import math
import operator
from functools import reduce
import moviepy.editor as mp


class gifix:
    def __init__(self, file):
        self._file = file
        self.frames = None
        with Image.open(file) as im:
            self._duration = im.info['duration']
            self._loop = im.info['loop']
            self.frames = ImageSequence.all_frames(im)
            print("gif image have {} frames. [init] ".format(len(self.frames)))
            print("gif info: {}\r\n".format(im.info))

    def frames(self):
        return self.frames

    def del_same_frames(self, threshold):
        """
        删除图片帧中相似的帧
        """
        rmss = []
        for index in range(1, len(self.frames)):
            rmss.append(self._image_rms(self.frames[index - 1], self.frames[index]))
        for index in range(len(rmss) - 1, 0, -1):
            if rmss[index] < threshold:
                del self.frames[index]
        print("gif image have {} frames. [same del threshold {}]".format(len(self.frames), threshold))
        return self.frames

    def compress_frames(self, rate):
        """
        使用抽帧算法压缩gif帧
        """
        self.frames = [frame for index, frame in enumerate(self.frames) if index % rate == 0]
        print("gif image have {} frames. [compress rate {}]".format(len(self.frames), rate))
        return self.frames

    def resize_frames(self, scale):
        """
        等比例改变gif帧的大小
        """
        w1 = self.frames[0].size[0]
        h1 = self.frames[0].size[1]
        w2 = int(w1 * scale)
        h2 = int(h1 * scale)
        self.frames = [frame.resize((w2, h2), Image.ANTIALIAS) for frame in self.frames]
        print("gif image size w-{}px h-{}px -> w-{}px h-{}px.".format(w1, h1, w2, h2))
        return self.frames

    def save_gif_sub_frames(self, folder):
        if not os.path.exists(folder):
            os.makedirs(folder)
        for index, frame in enumerate(self.frames):
            frame = frame.convert('RGB')
            frame.save('{}/'.format(folder) + folder + '_sub_' + str(index).rjust(5, '0') + '.jpg',
                       quality=100, subsampling=0)
        print("gif image frames save to {}.".format(folder))

    def save_gif(self, name, loop=None, duration=None):
        """
        保存gif
        """
        if not loop:
            loop = self._loop
        if not duration:
            duration = self._duration
        frames = self.frames[::]
        frames[0].save(name, save_all=True, optimize=False,
                       append_images=frames[1:], loop=loop, duration=duration, disposal=2)
        print("gif image frames saved as {}.".format(name))

    def save_gif_reverse(self, name, loop=None, duration=None):
        """
        保存倒放gif
        """
        if not loop:
            loop = self._loop
        if not duration:
            duration = self._duration
        print(loop, duration)
        frames = self.frames[::-1]
        frames[0].save(name, save_all=True, optimize=False,
                       append_images=frames[1:], loop=loop, duration=duration, disposal=2)
        print("gif image frames reversed saved as {}.".format(name))

    def save_as_mp4(self):
        vfc = mp.VideoFileClip(self._file)
        vfc.write_videofile(self._file[:-3] + 'mp4', fps=24)

    @staticmethod
    def _image_rms(image1, image2):
        """
        计算2个图片的相似度，算法：RMS
        """
        h1 = image1.histogram()
        h2 = image2.histogram()
        rms = math.sqrt(reduce(operator.add, list(map(lambda a, b: (a - b) ** 2, h1, h2))) / len(h1))
        return rms


def mp4_to_gif(mp4, start=None, end=None, fps=5):
    cache = mp.VideoFileClip(mp4)
    start = 0 if not start else start
    end = cache.duration if not end else end
    cache = cache.subclip(start, end)
    cache.write_gif(mp4[:-3] + 'gif', fps=fps)


def mp4_cut(mp4, start=None, end=None, fps=24):
    cache = mp.VideoFileClip(mp4)
    start = 0 if not start else start
    end = cache.duration if not end else end
    cache = cache.subclip(start, end)
    cache.to_videofile('cut' + mp4, fps=fps, remove_temp=True)


def sub_frames_to_gif(folder, ext, gif_name, gif_duration=200, gif_loop=65535, reverse=False):
    images = []
    for root, dirs, files in os.walk(folder):
        for file in files:
            if file.endswith(ext):
                images.append(os.path.join(root, file))
    images.sort(reverse=reverse)
    im = [Image.open(_) for _ in images]
    im[0].save(gif_name, save_all=True, optimize=False,
               append_images=im[1:], loop=gif_loop, duration=gif_duration, disposal=2)
